Ovládnite asynchrónnu iteráciu v JavaScripte pomocou slučky 'for await...of' a vlastných pomocníkov pre asynchrónne iterátory. Zlepšite spracovanie prúdov a manipuláciu s dátami na praktických príkladoch.
Pomocník pre asynchrónny iterátor v JavaScripte: For Each - Iterácia pri spracovaní prúdov
Asynchrónne programovanie je základným kameňom moderného vývoja v JavaScripte, ktorý umožňuje aplikáciám spracovávať časovo náročné operácie bez blokovania hlavného vlákna. Asynchrónne iterátory, predstavené v ECMAScript 2018, poskytujú výkonný mechanizmus na asynchrónne spracovanie dátových prúdov. Tento blogový príspevok sa ponára do konceptu asynchrónnych iterátorov a ukazuje, ako implementovať asynchrónnu pomocnú funkciu 'for each' na zefektívnenie spracovania prúdov.
Pochopenie asynchrónnych iterátorov
Asynchrónny iterátor je objekt, ktorý zodpovedá rozhraniu AsyncIterator. Definuje metódu next(), ktorá vracia promise, ktorá sa vyrieši na objekt s dvoma vlastnosťami:
value: Ďalšia hodnota v sekvencii.done: Booleovská hodnota, ktorá udáva, či iterátor dokončil svoju činnosť.
Asynchrónne iterátory sa bežne používajú na konzumáciu dát z asynchrónnych zdrojov, ako sú sieťové prúdy, súborové systémy alebo databázy. Slučka for await...of poskytuje pohodlnú syntax na iteráciu cez asynchrónne iterovateľné objekty.
Príklad: Asynchrónne čítanie zo súboru
Zoberme si scenár, kde potrebujete čítať veľký súbor riadok po riadku bez blokovania hlavného vlákna. Môžete to dosiahnuť pomocou asynchrónneho iterátora:
const fs = require('fs');
const readline = require('readline');
async function* readFileLines(filePath) {
const fileStream = fs.createReadStream(filePath);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
for await (const line of rl) {
yield line;
}
}
async function processFile(filePath) {
for await (const line of readFileLines(filePath)) {
console.log(`Line: ${line}`);
}
}
// Example usage
processFile('path/to/your/file.txt');
V tomto príklade je readFileLines asynchrónna generátorová funkcia, ktorá postupne vracia (yield) každý riadok súboru tak, ako je čítaný. Funkcia processFile potom iteruje cez riadky pomocou for await...of, pričom každý riadok spracováva asynchrónne.
Implementácia asynchrónneho pomocníka 'For Each'
Hoci je slučka for await...of užitočná, môže sa stať zdĺhavou, keď potrebujete vykonať zložité operácie na každom prvku v prúde. Asynchrónna pomocná funkcia 'for each' môže tento proces zjednodušiť zapuzdrením logiky iterácie.
Základná implementácia
Tu je základná implementácia asynchrónnej funkcie 'for each':
async function asyncForEach(iterable, callback) {
for await (const item of iterable) {
await callback(item);
}
}
Táto funkcia prijíma asynchrónny iterovateľný objekt a callback funkciu ako argumenty. Iteruje cez iterovateľný objekt pomocou for await...of a pre každú položku volá callback funkciu. Callback funkcia by tiež mala byť asynchrónna, ak chcete počkať na jej dokončenie pred prechodom na ďalšiu položku.
Príklad: Spracovanie dát z API
Predpokladajme, že načítavate dáta z API, ktoré vracia prúd položiek. Môžete použiť asynchrónneho pomocníka 'for each' na spracovanie každej položky hneď, ako dorazí:
async function* fetchDataStream(url) {
const response = await fetch(url);
const reader = response.body.getReader();
const decoder = new TextDecoder();
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
return;
}
// Assuming the API returns JSON chunks
const chunk = decoder.decode(value);
const items = JSON.parse(`[${chunk.replace(/\}\{/g, '},{')}]`); //Split chunks into valid json array
for(const item of items){
yield item;
}
}
} finally {
reader.releaseLock();
}
}
async function processItem(item) {
// Simulate an asynchronous operation
await new Promise(resolve => setTimeout(resolve, 100));
console.log(`Processing item: ${JSON.stringify(item)}`);
}
async function main() {
const apiUrl = 'https://api.example.com/data'; // Replace with your API endpoint
await asyncForEach(fetchDataStream(apiUrl), processItem);
console.log('Finished processing data.');
}
// Example usage
main();
V tomto príklade funkcia fetchDataStream načítava dáta z API a postupne vracia (yield) každú položku, ako je prijatá. Funkcia processItem simuluje asynchrónnu operáciu na každej položke. Pomocník asyncForEach potom zjednodušuje logiku iterácie a spracovania.
Vylepšenia a úvahy
Spracovanie chýb
Je kľúčové spracovať chyby, ktoré sa môžu vyskytnúť počas asynchrónnej iterácie. Callback funkciu môžete obaliť do bloku try...catch, aby ste zachytili a spracovali výnimky:
async function asyncForEach(iterable, callback) {
for await (const item of iterable) {
try {
await callback(item);
} catch (error) {
console.error(`Error processing item: ${item}`, error);
// You can choose to re-throw the error or continue processing
}
}
}
Riadenie súbežnosti
V predvolenom nastavení asynchrónny pomocník 'for each' spracováva položky sekvenčne. Ak potrebujete spracovávať položky súbežne, môžete použiť fond Promise (Promise pool) na obmedzenie počtu súbežných operácií:
async function asyncForEachConcurrent(iterable, callback, concurrency) {
const executing = [];
for await (const item of iterable) {
const p = callback(item).then(() => executing.splice(executing.indexOf(p), 1));
executing.push(p);
if (executing.length >= concurrency) {
await Promise.race(executing);
}
}
await Promise.all(executing);
}
async function processItem(item) {
// Simulate an asynchronous operation
await new Promise(resolve => setTimeout(resolve, 100));
console.log(`Processing item: ${JSON.stringify(item)}`);
}
async function main() {
const apiUrl = 'https://api.example.com/data'; // Replace with your API endpoint
await asyncForEachConcurrent(fetchDataStream(apiUrl), processItem, 5); // Concurrency of 5
console.log('Finished processing data.');
}
V tomto príklade asyncForEachConcurrent obmedzuje počet súbežných vykonaní callbacku na zadanú úroveň súbežnosti. To môže zlepšiť výkon pri práci s veľkými prúdmi dát.
Zrušenie
V niektorých prípadoch možno budete musieť proces iterácie predčasne zrušiť. Môžete to dosiahnuť pomocou AbortController:
async function asyncForEach(iterable, callback, signal) {
for await (const item of iterable) {
if (signal && signal.aborted) {
console.log('Iteration aborted.');
return;
}
await callback(item);
}
}
async function main() {
const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => {
controller.abort(); // Abort after 2 seconds
}, 2000);
const apiUrl = 'https://api.example.com/data'; // Replace with your API endpoint
await asyncForEach(fetchDataStream(apiUrl), processItem, signal);
console.log('Finished processing data.');
}
V tomto príklade funkcia asyncForEach kontroluje vlastnosť signal.aborted pred každou iteráciou. Ak je signál zrušený, iterácia sa zastaví.
Aplikácie v reálnom svete
Asynchrónne iterátory a asynchrónny pomocník 'for each' môžu byť aplikované na širokú škálu reálnych scenárov:
- Potrubia na spracovanie dát: Spracovanie veľkých dátových súborov z databáz alebo súborových systémov.
- Dátové prúdy v reálnom čase: Spracovanie dát z webových soketov, front správ alebo senzorových sietí.
- Konzumácia API: Načítavanie a spracovanie dát z API, ktoré vracajú prúdy položiek.
- Spracovanie obrazu a videa: Spracovanie veľkých mediálnych súborov po častiach.
- Analýza logov: Analýza veľkých logovacích súborov riadok po riadku.
Príklad - Medzinárodné akciové dáta: Zoberme si aplikáciu, ktorá načítava v reálnom čase kurzy akcií z rôznych medzinárodných búrz. Asynchrónny iterátor môže byť použitý na streamovanie dát a asynchrónny 'for each' môže spracovať každý kurz, aktualizujúc používateľské rozhranie najnovšími cenami. Toto sa dá použiť na zobrazenie aktuálnych kurzov akcií spoločností ako:
- Tencent (Čína): Načítavanie dát o akciách veľkej medzinárodnej technologickej spoločnosti
- Tata Consultancy Services (India): Zobrazovanie aktualizácií akcií od vedúcej spoločnosti v oblasti IT služieb
- Samsung Electronics (Južná Kórea): Ukazovanie kurzov akcií od globálneho výrobcu elektroniky
- Toyota Motor Corporation (Japonsko): Monitorovanie cien akcií medzinárodného výrobcu automobilov
Záver
Asynchrónne iterátory a asynchrónny pomocník 'for each' poskytujú silný a elegantný spôsob na asynchrónne spracovanie dátových prúdov v JavaScripte. Zapuzdrením logiky iterácie môžete zjednodušiť svoj kód, zlepšiť čitateľnosť a zvýšiť výkon vašich aplikácií. Spracovaním chýb, riadením súbežnosti a umožnením zrušenia môžete vytvárať robustné a škálovateľné asynchrónne potrubia na spracovanie dát.